﻿using System;
using System.ComponentModel.DataAnnotations;

namespace IntellectShop.Common
{
	public class MoneyValidationAttribute : ValidationAttribute
	{
		public override bool IsValid(object value)
		{
			Money money = (Money)value;
			return money.Amount >= 0 && money.Amount < 1000000000m;
		}
	}

	public struct Money : IConvertible
	{
		public static readonly Money MinValue = new Money { Amount = 0m, Currency = Currency.RUB };

		public static readonly Money MaxValue = new Money { Amount = Int32.MaxValue, Currency = Currency.RUB };

		public const int DecimalPlace = 2;

		public Currency Currency { get; set; }

		public decimal Amount { get; set; }

		public override string ToString()
		{
			return String.Format("{0:###,###,###,###,##0.00} {1}", this.Amount, this.Currency.ToLocalizedString());
		}

		public static Money operator +(Money a, Money b)
		{
			if (a.Currency != b.Currency)
				throw new ArgumentException("Currency not equals.");

			return new Money{Amount = a.Amount + b.Amount, Currency = a.Currency};
		}

		public static Money operator *(Money a, Money b)
		{
			if (a.Currency != b.Currency)
				throw new ArgumentException("Currency not equals.");

			return new Money { Amount = a.Amount * b.Amount, Currency = a.Currency };
		}

		public static Money operator *(Money a, int b)
		{
			return new Money { Amount = a.Amount * b, Currency = a.Currency };
		}

		public static Money operator *(int b, Money a)
		{
			return new Money { Amount = a.Amount * b, Currency = a.Currency };
		}

		#region IConvertible Members

		TypeCode IConvertible.GetTypeCode()
		{
			return TypeCode.Object;
		}

		bool IConvertible.ToBoolean(IFormatProvider provider)
		{
			throw new InvalidCastException();
		}

		byte IConvertible.ToByte(IFormatProvider provider)
		{
			throw new InvalidCastException();
		}

		char IConvertible.ToChar(IFormatProvider provider)
		{
			throw new InvalidCastException();
		}

		DateTime IConvertible.ToDateTime(IFormatProvider provider)
		{
			throw new InvalidCastException();
		}

		decimal IConvertible.ToDecimal(IFormatProvider provider)
		{
			return Amount;
		}

		double IConvertible.ToDouble(IFormatProvider provider)
		{
			return (double)Amount;
		}

		short IConvertible.ToInt16(IFormatProvider provider)
		{
			throw new InvalidCastException();
		}

		int IConvertible.ToInt32(IFormatProvider provider)
		{
			throw new InvalidCastException();
		}

		long IConvertible.ToInt64(IFormatProvider provider)
		{
			throw new InvalidCastException();
		}

		sbyte IConvertible.ToSByte(IFormatProvider provider)
		{
			throw new InvalidCastException();
		}

		float IConvertible.ToSingle(IFormatProvider provider)
		{
			throw new InvalidCastException();
		}

		string IConvertible.ToString(IFormatProvider provider)
		{
			return this.ToString();
		}

		object IConvertible.ToType(Type conversionType, IFormatProvider provider)
		{
			return Convert.ChangeType(Amount, conversionType);
		}

		ushort IConvertible.ToUInt16(IFormatProvider provider)
		{
			throw new InvalidCastException();
		}

		uint IConvertible.ToUInt32(IFormatProvider provider)
		{
			throw new InvalidCastException();
		}

		ulong IConvertible.ToUInt64(IFormatProvider provider)
		{
			throw new InvalidCastException();
		}

		#endregion
	}
}
